﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Snowdreamist.Collection;
using Snowdreamist.ComponentModel;

namespace Snowdreamist.Windows.Data
{
    public class LanguageManager : ThreadSafeNotifyPropertyChanged
    {
        #region singleton

        private static volatile LanguageManager _manager;
        private static readonly object _syncRoot = new object();

        public static LanguageManager Current
        {
            get
            {
                if (_manager == null)
                    lock (_syncRoot)
                        if (_manager == null)
                            _manager = new LanguageManager();
                return _manager;
            }
        }

        #endregion singleton

        static LanguageManager()
        {
            Converter = new LanguageResourceConverter();
        }

        /// <summary>
        /// Language resources converter
        /// Convert from key to resource object
        /// </summary>
        public static LanguageResourceConverter Converter { get; set; }

        protected LanguageManager()
        {
            this.Culture = CultureInfo.CurrentCulture;
        }

        #region Culture

        private CultureInfo _Culture;

        /// <summary>
        /// Culture
        /// </summary>
        public CultureInfo Culture
        {
            get { return this._Culture; }
            set
            {
                if (this._Culture != value)
                {
                    this._Culture = value;
                    this.OnPropertyChanged("Culture");
                }
            }
        }

        #endregion Culture

        public IEnumerable<CultureInfo> SupportedCultures
        {
            get
            {
                return this._langDict.Keys.ToArray();
            }
        }

        public virtual void LoadLanguageResources(LanguageResources res)
        {
            if (res == null)
                throw new ArgumentNullException("res");
            foreach (var x in res)
                this.RegisterLanguage(x);
        }

        /// <summary>
        /// Register lanaguage
        /// </summary>
        /// <param name="culture"></param>
        /// <param name="langResource"></param>
        public virtual void RegisterLanguage(LanguageResource langResource)
        {
            if (langResource == null)
                throw new ArgumentNullException("langResource");
            lock (this)
            {
                var cul = langResource.GetCulture();
                if (this._langDict.ContainsKey(cul))
                    throw new InvalidOperationException("Culture " + cul.EnglishName + "has already registerred");
                this._langDict[cul] = langResource;
            }
        }

        /// <summary>
        /// Unregister language
        /// </summary>
        /// <param name="culture"></param>
        public virtual void UnregisterLanguage(CultureInfo culture)
        {
            if (culture == null)
                throw new ArgumentNullException("culture");
            lock (this)
            {
                if (this._langDict.ContainsKey(culture))
                    this._langDict.Remove(culture);
            }
        }

        /// <summary>
        /// Get resource for specific langauage
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual object GetResource(string key)
        {
            LanguageResource langRes = null;

            if (!this._langDict.TryGetValue(this.Culture, out langRes))
            {
                // fail to get language resource for this.Culture, try default one
                if (!(this._langDict.TryGetValue(CultureInfo.CurrentCulture, out langRes)))
                {
                    // not found, return none
                    return null;
                }
            }

            return langRes.GetResource(key);
        }

        public virtual object GetResource(string key, CultureInfo culture)
        {
            if (culture == null)
                throw new ArgumentNullException("culture");

            LanguageResource langRes = null;

            if (!this._langDict.TryGetValue(culture, out langRes))
            {
                // not found, return none
                return null;
            }

            return langRes.GetResource(key);
        }

        #region private

        /// <summary>
        /// All languages
        /// </summary>
        private readonly Dictionary<CultureInfo, LanguageResource> _langDict = new Dictionary<CultureInfo, LanguageResource>();

        #endregion private
    }
}